﻿using CyUSB;
using debugger;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace debugger
{
    public class Base : Form
    {
        public string BaseType = "cy7c68031a";
        public int packageSize = 1024;

        void usbDevices_DeviceRemoved(object sender, EventArgs e)
        {
            Console.WriteLine("usbDevices_DeviceRemoved");
            setDevice();
        }
        void usbDevices_DeviceAttached(object sender, EventArgs e)
        {
            Console.WriteLine("usbDevices_DeviceAttached");
            setDevice();
        }
        public bool isBasic;
        public void setDevice()
        {
            Console.WriteLine("setDevice start");
            loopDevice = usbDevices[0x04b4, 0x1004] as CyUSBDevice;
            CyFX2Device progDevice = usbDevices[0x04b4, 0x8613] as CyFX2Device;

            if (loopDevice == null && progDevice != null)
            {
                //progDevice.LoadExternalRam(@"D:\MyCode.github\cy7c68013a\Bulkloop.firm.my\bulkloop.hex");
                //progDevice.LoadExternalRam(@"D:\MyCode.github\cy7c68013a\test1004slavefifo\bulkloop.hex");
                //progDevice.LoadExternalRam(@"debugger.cy7c68013a\cy7c68013a_slavefifo_firmwarepio\bulkloop.hex");
                Console.WriteLine("upload start");
                progDevice.LoadExternalRam(@"bulkloop.hex");
                Console.WriteLine("upload end");
            }
            if (loopDevice == null && progDevice == null)
            {
                Console.WriteLine("no dev");
            }

            if (loopDevice != null)
            {
                this.Text = loopDevice.FriendlyName;
                Console.WriteLine("found dev" + this.Text);
                //EndpointAddress 8:in from cy  0:out to cy
                outCmdEndpoint = loopDevice.EndPointOf(0x01) as CyBulkEndPoint;
                inCmdEndpoint = loopDevice.EndPointOf(0x81) as CyBulkEndPoint;
                outEndpoint = loopDevice.EndPointOf(0x02) as CyBulkEndPoint;
                inEndpoint = loopDevice.EndPointOf(0x86) as CyBulkEndPoint;
                if (outEndpoint.MaxPktSize != 512)
                {
                    MessageBox.Show("MaxPktSize != 512");
                    Console.WriteLine("MaxPktSize = " + outEndpoint.MaxPktSize);
                }
                outEndpoint.TimeOut = 1000;
                inEndpoint.TimeOut = 1000;
                outCmdEndpoint.TimeOut = 1000;
                inCmdEndpoint.TimeOut = 1000;

                outEndpoint.Abort();
                inEndpoint.Abort();
                outCmdEndpoint.Abort();
                inCmdEndpoint.Abort();

                outEndpoint.Reset();
                inEndpoint.Reset();
                outCmdEndpoint.Reset();
                inCmdEndpoint.Reset();

                Thread.Sleep(10);
                try
                {
                    //byte[] data = new byte[16];
                    //int  xferLen = 16;
                    //bool bResult = outEndpoint.XferData(ref data, ref xferLen);
                    //if (!bResult) { 
                    //}

                    //uint temp = sendCmdRet(0x01, 123);
                    //isBasic = (temp & 0x10) != 0;
                    //temp = temp & 0x0F;
                    //if (temp != 0x0A)
                    //{
                    //    this.Text = "ERROR";
                    //    //Application.Exit();
                    //}
                    afterConnect();
                }
                catch (Exception ex) {
                    this.Text = "Exception";
                }

            }
            else
            {
                this.Text = "Bulkloop - no device";
            }
        }

        USBDeviceList usbDevices = null;
        CyUSBDevice loopDevice = null;
        public CyBulkEndPoint inEndpoint = null;
        public CyBulkEndPoint outEndpoint = null;
        public CyBulkEndPoint inCmdEndpoint = null;
        public CyBulkEndPoint outCmdEndpoint = null;

        public delegate void AfterConnect();

        AfterConnect afterConnect;
        public bool connect(AfterConnect afterConnect)
        {
            this.afterConnect = afterConnect;
            if (usbDevices != null)
            {
                usbDevices.Dispose();
            }

            // Create a list of CYUSB devices
            Console.WriteLine("init start");
            usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
            Console.WriteLine("init end");

            //Adding event handlers for device attachment and device removal
            usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
            usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);

            //The below function sets the device with particular VID and PId and searches for the device with the same VID and PID.
            setDevice();
            return true;
        }
        private uint readFromPort()
        {
            int size = 4;
            bool bResult;
            byte[] inData = new byte[4];
            Stopwatch sw = new Stopwatch();
            sw.Start();
            while (true)
            {
                int xferLen = size;
                bResult = inCmdEndpoint.XferData(ref inData, ref xferLen);
                if (bResult)
                {
                    break;
                }
                if (sw.ElapsedMilliseconds > 1000)
                {
                    throw new Exception();
                }
            }
            uint ret = 0;
            ret |= (uint)inData[0] << 0;
            ret |= (uint)inData[1] << 8;
            ret |= (uint)inData[2] << 16;
            ret |= (uint)inData[3] << 24;
            return ret;
        }

        public uint sendCmdRet(byte cmd, uint? udata = null)
        {
            int size = 5;
            bool bResult;
            byte[] outData = new byte[5];
            outData[0] = (byte)cmd;
            if (udata == null)
            {
                udata = 0;
            }
            outData[1] = (byte)(udata >> 0);
            outData[2] = (byte)(udata >> 8);
            outData[3] = (byte)(udata >> 16);
            outData[4] = (byte)(udata >> 24);
            int xferLen = size;
            bResult = outCmdEndpoint.XferData(ref outData, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
            uint val = 0;
            val = readFromPort();
            return val;
        }

        public void sendCmd(byte cmd, uint? udata = null)
        {
            int size = 5;
            bool bResult;
            byte[] outData = new byte[5];
            outData[0] = (byte)cmd;
            if (udata == null)
            {
                udata = 0;
            }
            outData[1] = (byte)(udata >> 0);
            outData[2] = (byte)(udata >> 8);
            outData[3] = (byte)(udata >> 16);
            outData[4] = (byte)(udata >> 24);
            int xferLen = size;
            bResult = outCmdEndpoint.XferData(ref outData, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
            uint val = 0;
            val = readFromPort();
            return;
        }
        public void sendCmdNoRes(byte cmd, uint? udata = null)
        {
            int size = 5;
            bool bResult;
            byte[] outData = new byte[5];
            outData[0] = (byte)cmd;
            if (udata == null)
            {
                udata = 0;
            }
            outData[1] = (byte)(udata >> 0);
            outData[2] = (byte)(udata >> 8);
            outData[3] = (byte)(udata >> 16);
            outData[4] = (byte)(udata >> 24);
            int xferLen = size;
            bResult = outCmdEndpoint.XferData(ref outData, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
            return;
        }
        
        static readonly int PAGESIZE = 1024;

        bool is8bit = false;
        uint channel = 0;
        uint receive_phase = 0 << 3;
        uint send_phase = 1 << 3;


        public bool receive(byte[] data, uint length)//read
        {
            sendCmd(0x05);

            bool bResult;

            int xferLen;

            xferLen = (int)length;
            bResult = inEndpoint.XferData(ref data, ref xferLen);
            if (!bResult)
            {
                throw new Exception("receive:" + xferLen);
            }

            sendCmd(0x04);
            sendCmd(0x03);
            sendCmd(0x02);
            return true;
        }
        public bool send(byte[] data, uint length)//write
        {
            sendCmd(0x05);
            int xferLen;
            bool bResult;

            xferLen = (int)length;
            bResult = outEndpoint.XferData(ref data, ref xferLen);
            if (!bResult)
            {
                throw new Exception("send:" + xferLen);
            }

            
            sendCmd(0x04);
            sendCmd(0x03);
            sendCmd(0x02);
            return true;
        }
        byte[] data2 = new byte[1024];

        public const byte VGA_CONTROL_BY_DEBUGGER = 0x06;

        public bool fast = true;



        public void getVGA(byte[] data, uint baseAddr, bool fast341, bool reset)//read
        {
            uint frameSize = 1024 * (1024 + 512);
            //frameSize = 1024 * 1024;

            sendCmd(Form1.SET_DEBUG_ADDRESS, baseAddr);
            sendCmd(Form1.SET_DEBUG_LENGTH, frameSize);
            sendCmdNoRes(Form1.VGA_TRANS);


            sendCmd(0x05);

            bool bResult;

            int xferLen;

            xferLen = (int)frameSize;
            bResult = inEndpoint.XferData(ref data, ref xferLen);
            if (!bResult)
            {
                throw new Exception();
            }
            sendCmd(0x04);
            sendCmd(0x03);
            sendCmd(0x02);

        }



        public bool fpga2pcReq()
        {
            return false;
        }


        public bool pc2fpgaReq()
        {
            return false;
        }



        public bool fpga2pcTrans(ref byte[] buff2, ref int xferLen)
        {
            return false;
        }


        public bool pc2fpgaTrans(ref byte[] buff2, ref int xferLen)
        {
            return false;
        }



        
    }
}
